.dropdown
的內容都透過 css 隱藏起來了。.dropdown {
/* 透明度0 */
opacity: 0;
position: absolute;
overflow: hidden;
padding: 20px;
top: -20px;
border-radius: 2px;
transition: all 0.5s;
transform: translateY(100px);
will-change: opacity;
/* 排版:隱藏 */
display: none;
}
而下方又有這兩組 css,代表的是當外層容器有trigger-enter
、trigger-enter-active
時選單要變更排版及透明度設定。
.trigger-enter .dropdown {
display: block;
}
.trigger-enter-active .dropdown {
opacity: 1;
}
負責下拉選單背景的.dropdownBackground
容器也有設定透明度隱藏,及若有.open
class 時解除隱藏
.dropdownBackground {
/* . */
/* . 其餘css設定 */
/* . */
opacity: 0;
}
.dropdownBackground.open {
opacity: 1;
}
因此我們要做的是即是在適當的位置添加事件監聽器,當滑鼠滑入時加入 class 當滑鼠移出時移除 class,看一下結構我們選擇使用<ul class="cool">
清單下的每個<li>
// 選取每個nav li 節點
const li = document.querySelectorAll(".cool>li");
// 選取白框背景容器
const background = document.querySelector(".dropdownBackground");
// 每個都增加滑鼠滑入監聽器及滑鼠移出監聽器
li.forEach((node) => {
node.addEventListener("mouseenter", handleMouseenter);
});
li.forEach((node) => {
node.addEventListener("mouseleave", handleMouseleave);
});
function handleMouseenter(e) {
this.classList.add("trigger-enter", "trigger-enter-active");
background.classList.add("open");
}
function handleMouseleave(e) {
this.classList.remove("trigger-enter", "trigger-enter-active");
background.classList.remove("open");
}
handleMouseenter
函式將背景容器的寬高變成觸發事件的下拉式選單寬高,以及位移背景容器到觸發事件的下拉式選單位置,即可以達到題目要求效果。// 全域新增兩個變數,因為nav上有設定position:relative;
// 所以會造成位置偏移要扣掉nav.getBoundingClientRect的top及left
const nav = document.querySelector(".top");
const navCoords = nav.getBoundingClientRect();
// 改寫`handleMouseenter`函式
function handleMouseenter(e) {
this.classList.add("trigger-enter");
// 因為dropdownBackgroundb容器css有設定transition,所以opacity恢復透明度需要延遲一下
setTimeout(() => {
this.classList.add("trigger-enter-active");
}, 150);
background.classList.add("open");
// 選取觸發事件容器內的下拉式選單
const dropdown = this.querySelector(".dropdown");
// display取消隱藏後,才能取得邊界矩形
const dropdownCoords = dropdown.getBoundingClientRect();
const coords = {
height: dropdownCoords.height,
width: dropdownCoords.width,
// 因為nav上有設定position:relative;
// 所以會造成位置偏移要扣掉nav.getBoundingClientRect的top及left
top: dropdownCoords.top - navCoords.top,
left: dropdownCoords.left - navCoords.left,
};
// 將背景容器寬高,及位置依序設定
background.style.setProperty("width", `${coords.width}px`);
background.style.setProperty("height", `${coords.height}px`);
background.style.setProperty(
"transform",
`translate(${coords.left}px, ${coords.top}px)`
);
}